#include <stdarg.h>

#include "types.h"
#include "param.h"
#include "spinlock.h" // 需要此文件来定义 struct spinlock
#include "defs.h"     // 需要此文件来获取 initlock 的函数原型

// 声明 uart.c 中的函数
void uart_putc(char c);

static void printint(int xx, int base, int sign);
static void printptr(uint64 x);
static void printuint64(uint64 x, int base);  // 添加这一行

static struct spinlock pr_lock;

// 初始化 printf 功能, 为 printf 创建一个锁
void
printfinit(void)
{
  initlock(&pr_lock, "pr");
}

// 格式化输出到控制台
void
printf(char *fmt, ...)
{
  va_list ap;
  int i, c;
  char *s;

  if (fmt == 0)
    panic("null fmt");

  // acquire(&pr_lock); // 如果实现了多核，需要加锁

  va_start(ap, fmt);
  for(i = 0; (c = fmt[i] & 0xff) != 0; i++){
    if(c != '%'){
      uart_putc(c);
      continue;
    }
    c = fmt[++i] & 0xff;
    if(c == 0)
      break;
    switch(c){
    case 'd':
      printint(va_arg(ap, int), 10, 1);
      break;
    case 'x':
      printint(va_arg(ap, int), 16, 1);
      break;
    case 'p':
      printptr(va_arg(ap, uint64));
      break;
    case 's':
      if((s = va_arg(ap, char*)) == 0)
        s = "(null)";
      for(; *s; s++)
        uart_putc(*s);
      break;
    case 'l':
      // 支持 %lu (long unsigned)
      c = fmt[++i] & 0xff;
      if(c == 'u') {
        printuint64(va_arg(ap, uint64), 10);
      } else {
        // 未知的 %l 格式，打印原样
        uart_putc('%');
        uart_putc('l');
        if(c != 0) {
          uart_putc(c);
        }
      }
      break;
    case '%':
      uart_putc('%');
      break;
    default:
      // 打印一个 '%' 和未知的字符
      uart_putc('%');
      uart_putc(c);
      break;
    }
  }

  // release(&pr_lock); // 如果实现了多核，需要解锁
}

// 遇到无法恢复的错误时中止。
// 打印 "panic: <s_>" 然后进入死循环。
void
panic(char *s)
{
  printf("panic: %s\n", s);
  for(;;)
    ;
}

static char digits[] = "0123456789abcdef";

static void
printint(int xx, int base, int sign)
{
  char buf[16];
  int i;
  uint x;

  if(sign && (sign = xx < 0))
    x = -xx;
  else
    x = xx;

  i = 0;
  do {
    buf[i++] = digits[x % base];
  } while((x /= base) != 0);

  if(sign)
    buf[i++] = '-';

  while(--i >= 0)
    uart_putc(buf[i]);
}

static void
printptr(uint64 x)
{
  int i;
  uart_putc('0');
  uart_putc('x');
  for (i = 0; i < (sizeof(uint64) * 2); i++, x <<= 4)
    uart_putc(digits[x >> (sizeof(uint64) * 8 - 4)]);
}

static void
printuint64(uint64 x, int base)
{
  char buf[32];
  int i;

  i = 0;
  do {
    buf[i++] = digits[x % base];
  } while((x /= base) != 0);

  while(--i >= 0)
    uart_putc(buf[i]);
}